package com.province.platform.core.utils;

import com.province.platform.common.enums.CommonErrorCode;
import com.province.platform.common.enums.ContainerType;
import com.province.platform.common.enums.PluginType;
import com.province.platform.common.exception.PlatformException;
import com.province.platform.common.plugin.AbstractPlugin;
import com.province.platform.common.utils.Configuration;
import com.province.platform.core.classLoader.JarLoader;
import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 插件加载器
 */
public class LoadUtils {
    private static final String PLUGIN_NAME_FORMAT = "plugin.%s.%s";
    
    private static Configuration pluginRegisterCenter;

    private static Map<String, JarLoader> jarLoaderCenter = new HashMap<>();

    public static void bind(Configuration pluginConfiguration) {
        pluginRegisterCenter = pluginConfiguration;
    }

    public synchronized static JarLoader getJarLoader(PluginType pluginType, String pluginName) {
        Configuration pluginConf = getPluginConf(pluginType, pluginName);

        JarLoader jarLoader = jarLoaderCenter.get(generatePluginKey(pluginType, pluginName));

        if (Objects.isNull(jarLoader)) {
            String pluginPath = pluginConf.getString("path");
            if (StringUtils.isBlank(pluginPath)) {
                throw PlatformException.asPlatformException(CommonErrorCode.RUNTIME_ERROR, String.format("插件[%s]路径非法", pluginName));
            }
            jarLoader = new JarLoader(new String[]{pluginPath});
            jarLoaderCenter.put(generatePluginKey(pluginType, pluginName), jarLoader);
        }
        return jarLoader;
    }

    public static AbstractPlugin loadPlugin(PluginType pluginType, String pluginName, ContainerType containerType) {
        Class<? extends AbstractPlugin> clazz = loadPluginClass(pluginType, pluginName, containerType);
        try {
            AbstractPlugin plugin = clazz.newInstance();
            plugin.setPluginConfiguration(getPluginConf(pluginType, pluginName));
            return plugin;
        } catch (Exception e) {
           throw PlatformException.asPlatformException(CommonErrorCode.RUNTIME_ERROR, String.format("平台找不到plugin[%s]的%s的配置", pluginName, containerType));
        }
    }

    @SuppressWarnings("unchecked")
    private static synchronized Class<? extends AbstractPlugin> loadPluginClass(PluginType pluginType, String pluginName, ContainerType containerType) {
        Configuration pluginConf = getPluginConf(pluginType, pluginName);
        JarLoader jarLoader = getJarLoader(pluginType, pluginName);
        try {
            return (Class<? extends AbstractPlugin>) jarLoader.loadClass(pluginConf.getString("class") + "$" + containerType.value());
        } catch (Exception e) {
            throw PlatformException.asPlatformException(CommonErrorCode.RUNTIME_ERROR, e);
        }
    }

    private static String generatePluginKey(PluginType pluginType, String pluginName) {
        return String.format(PLUGIN_NAME_FORMAT, pluginType.value(), pluginName);
    }

    private static Configuration getPluginConf(PluginType pluginType, String pluginName) {
        Configuration pluginConf = pluginRegisterCenter.getConfiguration(generatePluginKey(pluginType, pluginName));

        if (Objects.isNull(pluginConf)) {
            throw PlatformException.asPlatformException(CommonErrorCode.PLUGIN_INIT_ERROR, String.format("平台找不到插件[%s]", pluginName));
        }

        return pluginConf;
    }
}
